/*
编写 : Hexh
时间 : 2012-5-24 15:41:23
*/

using System;
using System.Collections.Generic;
using HMIS.FrameWork.DomainBase;
using HMIS.Infrastructure.Core.Entities;
using HMIS.Infrastructure.Core.Repositories;
using HMIS.FrameWork;
using HMIS.Infrastructure.Core.Authority;
using System.Linq;

namespace HMIS.Infrastructure.Facade.Impl
{
	/// <summary>
	///	 the impl of IInfraApproveFacade
	/// </summary>
	public class InfraApproveFacadeImpl : IInfraApproveFacade
	{
		private readonly IInfraApproveRepository InfraApproveRepository;
		private readonly IInfraApproveLogRepository InfraApproveLogRepository;
		private readonly IHospUserRepository HospUserRepository;
		private readonly IInfraSmsRepository InfraSmsRepository;
		private readonly IInfraApproveHisRepository InfraApproveHisRepository;
		private readonly IInfraApproveHisStepRepository InfraApproveHisStepRepository;

		public InfraApproveFacadeImpl(IInfraApproveRepository InfraApproveRepository,
			IInfraApproveLogRepository InfraApproveLogRepository,
			IHospUserRepository HospUserRepository,
			IInfraSmsRepository InfraSmsRepository,
			IInfraApproveHisRepository InfraApproveHisRepository,
			IInfraApproveHisStepRepository InfraApproveHisStepRepository)
		{
			this.InfraApproveRepository = InfraApproveRepository;
			this.InfraApproveLogRepository = InfraApproveLogRepository;
			this.HospUserRepository = HospUserRepository;
			this.InfraSmsRepository = InfraSmsRepository;
			this.InfraApproveHisRepository = InfraApproveHisRepository;
			this.InfraApproveHisStepRepository = InfraApproveHisStepRepository;
		}

		#region IInfraApprove Entity Save,Get,Update,Delete

		public InfraApprove Get(string id)
		{
			return InfraApproveRepository.Get(id);
		}

		public InfraApprove Load(string id)
		{
			return InfraApproveRepository.Load(id);
		}

		public InfraApprove GetByDeptAndType(string deptId, string approveType)
		{
			return InfraApproveRepository.GetByDeptAndType(deptId, approveType);
		}

		public void SaveOrUpdate(InfraApprove entity)
		{
			this.InfraApproveRepository.SaveOrUpdate(entity);
		}

		public void Delete(string id)
		{
			InfraApproveRepository.Delete(id);
		}

		public void PhysicsDelete(string id)
		{
			InfraApproveRepository.PhysicsDelete(id);
		}

		public bool IsFieldExist(string fieldName, string fieldValue, string id)
		{
			return InfraApproveRepository.IsFieldExist(fieldName, fieldValue, id);
		}

		public bool IsFieldExist(string fieldName, string fieldValue, string id, string where)
		{
			return InfraApproveRepository.IsFieldExist(fieldName, fieldValue, id, where);
		}

		#endregion

		#region Query

		public IList<InfraApprove> GetAll()
		{
			return InfraApproveRepository.GetAll();
		}

		public IList<InfraApprove> GetPlist(string query, int start, int limit, string sort, string dir, List<DataFilter> filters, out long total)
		{
			return InfraApproveRepository.GetPlist(query, start, limit, sort, dir, filters, out total);
		}

		#endregion

		#region InfraApprove 审批流程

		/// <summary>
		/// 按审批流程增加待审批的记录
		/// </summary>
		/// <param name="approveId"></param>
		/// <param name="itemId"></param>
		/// <param name="smsContent">审批短信的内容</param>
		/// <returns></returns>
		/// <remarks>调用前需要判断当前审批单的状态。</remarks>
		public bool InitApproveLog(string approveId, string itemId, string smsContent)
		{
			InfraApprove approveInfo = this.Get(approveId);
			//删除已有的审批记录
			InfraApproveLogRepository.DeleteApplLogHist(itemId, approveId);
			//增加审批流程
			foreach (InfraApproveStep step in approveInfo.InfraApproveSteps)
			{
				InfraApproveLog logstep = new InfraApproveLog();
				logstep.ApproveItemId = itemId;
				logstep.ApproveId = step.ApproveId;
				logstep.ApproveStep = step.ApproveStep;
				logstep.UserId = step.UserId;
				logstep.Scale = step.Scale;
				logstep.AprCode = Guid.NewGuid().ToString().Substring(0, 8);
				logstep.ApproveState = "";
				InfraApproveLogRepository.SaveOrUpdate(logstep);
				//发送短信
				//string smsStr = smsContent + "\n[授权顺序:" + logstep.ApproveStep.ToString() + ",授权码:" + logstep.AprCode + "]";
				//InfraSmsRepository.SendSms(itemId, step.User.Mobitl, smsStr);
			}
			return true;
		}

		/// <summary>
		/// 发送审批短信
		/// </summary>
		/// <param name="stepId"></param>
		/// <returns></returns>
		public bool SendApproveCodeSms(string stepId)
		{
			InfraApproveHisStep stepEntity = this.InfraApproveHisStepRepository.Get(stepId);
			int newStep = this.GetApproveHisCurrentStep(stepEntity.ApproveHisId);
			
			string smsText = stepEntity.ApproveHis.SmsText + "\n审批授权码:" + stepEntity.AprCode;
			InfraSms smsSend = InfraSmsRepository.SendSms(stepEntity.ApproveHis.ApproveItemId, stepEntity.User.Mobitl, smsText);
			stepEntity.AprSmsState = smsSend.State.ToString();
			this.InfraApproveHisStepRepository.SaveOrUpdate(stepEntity);

			if (smsSend.State < 1)
				throw new Exception(smsSend.ToString());

			return smsSend.State > 0;
		}

		/// <summary>
		/// 返回审批步骤信息
		/// </summary>
		/// <param name="Id"></param>
		/// <returns></returns>
		public InfraApproveLog GetApproveLogStepById(string Id)
		{
			return InfraApproveLogRepository.Get(Id);
		}

		public InfraApproveHisStep ApproveProcess(string stepId, string inputUserNa, string inputUserPw, string inputApprCode, int inputApprState)
		{
			InfraApproveHisStep currentStep = this.InfraApproveHisStepRepository.Get(stepId);
			// 判断是否当前审批步骤
			int currentStepNo = this.GetApproveHisCurrentStep(currentStep.ApproveHisId);
			if (currentStepNo != currentStep.ApproveStep)
				throw new ValidationException("-1006,当前流程步骤为[" + currentStepNo + "],不可跨步骤审批.");

			if (currentStep.ApproveState != 0)
				throw new ValidationException("-1005,当前审批步骤已审批,不能重复审批!");

			if (String.IsNullOrEmpty(inputUserNa))
				throw new ValidationException("-1007,请输入用户名.");

			HospUser apUser = HospUserRepository.GetByName(inputUserNa);
			// 非本人操作
			if (currentStep.User.LoginName != inputUserNa)
			{
				if (HospUser.GetPwdMD5(inputUserPw) != apUser.Pwd || inputApprCode != currentStep.AprCode)
					throw new ValidationException("-1001,密码或授权码输入信息有误。");
			}
			else
			{
				if (String.IsNullOrEmpty(inputApprCode) && String.IsNullOrEmpty(inputUserPw))
					throw new ValidationException("-1004,必须输入密码或授权码.");
				if (!String.IsNullOrEmpty(inputApprCode) && inputApprCode != currentStep.AprCode)
					throw new ValidationException("-1002,密码或授权码输入信息有误。");
				if (!String.IsNullOrEmpty(inputUserPw) && HospUser.GetPwdMD5(inputUserPw) != apUser.Pwd)
					throw new ValidationException("-1003,密码或授权码输入信息有误。");
			}
			// 更新数据
			currentStep.ApproveUserId = apUser.Id;
			currentStep.ApproveDate = System.DateTime.Now;
			currentStep.ApproveState = inputApprState;

			int newStep = this.GetApproveHisCurrentStep(currentStep.ApproveHisId);
			// 审批通过
			if (newStep == 0)
			{
				currentStep.ApproveHis.ApproveState = 1;
				currentStep.ApproveHis.CurrentStep = newStep;
			}
			else if (newStep > 0)
			{
				currentStep.ApproveHis.ApproveState = 0;
				currentStep.ApproveHis.CurrentStep = newStep;
			}
			else
			{
				currentStep.ApproveHis.ApproveState = -1;
				currentStep.ApproveHis.CurrentStep = newStep;
			}
			InfraApproveHisStepRepository.SaveOrUpdate(currentStep);
			//InfraApproveHisRepository.SaveOrUpdate(currentStep.ApproveHis);

			return currentStep;
		}

		/// <summary>
		/// 提交审批，并返回审批流程状态
		/// </summary>
		/// <param name="logstep">审批步骤信息</param>
		/// <returns></returns>
		public int ProcedureApprove(InfraApproveLog logstep)
		{
			if (logstep == null)
				throw new ArgumentNullException("未找到审批步骤.");

			if (logstep.ApproveState != "")
				throw new ValidationException("当前审批步骤已审批,不能重复审批!");

			if (String.IsNullOrEmpty(logstep.InputAprCode) && String.IsNullOrEmpty(logstep.InputUserPwd))
				throw new ValidationException("审批码和密码不允许都为空");

			HospUser apUser = HospUserRepository.GetByName(logstep.InputUserLName);

			if (!String.IsNullOrEmpty(logstep.InputUserPwd) && apUser.Pwd != HospUser.GetPwdMD5(logstep.InputUserPwd))
				throw new ValidationException("输入信息有误");

			if (!String.IsNullOrEmpty(logstep.InputAprCode) && logstep.InputAprCode != logstep.AprCode)
				throw new ValidationException("输入信息有误。");

			if (apUser.Id != logstep.UserId)
			{
				if (String.IsNullOrEmpty(logstep.InputAprCode) || String.IsNullOrEmpty(logstep.InputUserPwd))
					throw new ValidationException("代理授权必须输入您的用户密码和短信审批码.");
			}

			int currentStep = GetApproveState(logstep.ApproveItemId);
			if (logstep.ApproveStep != currentStep)
				throw new ValidationException("不允许跨步骤审批." + currentStep);
			//更新
			logstep.ApproveUserId = apUser.Id;
			logstep.ApproveState = logstep.InputApprState;
			logstep.ApproveDate = System.DateTime.Now;
			InfraApproveLogRepository.SaveOrUpdate(logstep);

			return GetApproveState(logstep.ApproveItemId);
		}

		/// <summary>
		/// 计算返回当前审批步骤
		/// </summary>
		/// <param name="approveHisId"></param>
		/// <returns>当前步骤，如果返回0则审批通过. 小于0 表示当前申请已拒绝</returns>
		public int GetApproveHisCurrentStep(string approveHisId)
		{
			InfraApproveHis approveHis = this.InfraApproveHisRepository.Get(approveHisId);
			// 无需审批
			if (approveHis.ApprSteps.Count == 0)
				return 0;
			// 已拒绝
			if (approveHis.ApprSteps.FirstOrDefault(o => o.ApproveState == -1) != null)
				return -1; ;

			var procStep = approveHis.ApprSteps.Min(o => o.ApproveStep);
			// 审批成功的，计算审批权重
			var elements = from s in approveHis.ApprSteps
						   group s by new { s.ApproveStep }
							   into fStepGrp
							   select new
								{
									stepNum = fStepGrp.Key.ApproveStep,
									scaleSum = fStepGrp.Sum(s => s.ApproveState == 1 ? s.Scale : 0)
								};
			if (elements != null && elements.Count() != 0)
			{
				var procElements = from o in elements
								   where o.scaleSum < 100
								   select o.stepNum;
				if (procElements != null && procElements.Count() != 0)
					procStep = procElements.Min();
				else
					procStep = 0;
			}
			return procStep;
		}

		/// <summary>
		/// 根据审批流程返回审批单的状态
		/// </summary>
		/// <param name="approveItemId"></param>
		/// <returns>当前步骤，如果返回0则审批通过. 小于0 表示当前申请已拒绝</returns>
		public int GetApproveState(string approveItemId)
		{
			IList<InfraApproveLog> approveLogs = InfraApproveLogRepository.GetAllByItemId(approveItemId);
			if (approveLogs.Count == 0)
				return 0;

			int iscaleSum = 0, istep = approveLogs[0].ApproveStep;
			for (int i = 0; i < approveLogs.Count; i++)
			{
				if (approveLogs[i].ApproveState == "0")
					return 0 - istep;
				else
				{
					if (istep == approveLogs[i].ApproveStep)
						iscaleSum = approveLogs[i].ApproveState == "1" ? iscaleSum + approveLogs[i].Scale : iscaleSum;
					else
					{
						//判断上级步骤是否审批通过
						if (iscaleSum >= 100)
						{
							istep = approveLogs[i].ApproveStep;
							iscaleSum = approveLogs[i].ApproveState == "1" ? approveLogs[i].Scale : 0;
						}
						else
						{
							return istep;
						}
					}
				}
			}

			//表示已经通过审批
			if (iscaleSum >= 100)
				return 0;
			else
				return istep;
		}

		#endregion
	}
}
